﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;
using System.Threading;
using ICeFramework.DataManagement.Interfaces;
using ICeFramework.DataManagement.MSSql;
using System.Collections.Specialized;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;

namespace ICeFramework.Win.UI
{
    #region public enum NodeType
    /// <summary>
    /// 
    /// </summary>
    public enum NodeType
    {
        Server,
        DatabaseHolder,
        Database,
        TableHolder,
        Table,
        ColumnHolder,
        Column,
        KeyHolder,
        Key,
        ConstraintHolder,
        Constraint,
        TriggerHolder,
        Trigger,
        IndexHolder,
        Index,
        ViewHolder,
        View,
        SPHolder,
        SP,
        FunctionHolder,
        Function,

        ViewColumnHolder,
        ViewColumn,
        ViewTriggerHolder,
        ViewTrigger,
        ViewIndexHolder,
        ViewIndex,

        SPParamsHolder,
        SPParam,

        FunctionParamsHolder,
        FunctionParam,
    }
    #endregion

    public class DBTreeView : ICTreeView
    {
        private Server _server = null;
        private ImageList nodeImageList;
        private System.ComponentModel.IContainer components;
        private ContextMenuStrip contextMenu;
        private ToolStripMenuItem toolStripRefresh;
        private Dictionary<Type, StringCollection> _defaultInitFields = new Dictionary<Type, StringCollection>();

        private string _connectionString;
        #region public string ConnectionString
        /// <summary>
        /// Get/Sets the ConnectionString of the DBTreeView
        /// </summary>
        /// <value></value>
        public string ConnectionString
        {
            get { return _connectionString; }
            set { _connectionString = value; }
        }
        #endregion

        #region public DBTreeView()
        /// <summary>
        /// Initializes a new instance of the <b>DBTreeView</b> class.
        /// </summary>
        public DBTreeView()
        {
            InitializeComponent();
        }
        #endregion

        #region public void RefreshServer()
        /// <summary>
        /// 
        /// </summary>
        public void RefreshServer()
        {
            this.Nodes.Clear();

            SqlConnection conn = new SqlConnection(_connectionString);
            ServerConnection srvConn = new ServerConnection(conn);
            _server = new Server(srvConn);
            TreeNode serverTn = new TreeNode(_server.Name, 1, 1);
            serverTn.Tag = new DBObject(NodeType.Server);
            this.Nodes.Add(serverTn);



            TreeNode dbHolder = serverTn.Nodes.Add("Databases");
            dbHolder.Tag = new DBObject(NodeType.DatabaseHolder);
            dbHolder.Expand();
            if (!string.IsNullOrWhiteSpace(srvConn.DatabaseName))
            {
                Database db = _server.Databases[srvConn.DatabaseName];
                if (db != null)
                {
                    SetupDBNodes(dbHolder, db);
                }
            }
            else
            {
                foreach (Database db in _server.Databases)
                {
                    SetupDBNodes(dbHolder, db);
                }
            }
        }
        #endregion

        private void SetupDBNodes(TreeNode parent, Database db)
        {
            TreeNode dbTn = parent.Nodes.Add(db.Name, db.Name, 2, 2);
            dbTn.Tag = new DBObject(NodeType.Database);

            TreeNode tableNode = dbTn.Nodes.Add("Tables");
            tableNode.Tag = new DBObject(NodeType.TableHolder);
            tableNode.Nodes.Add("@@Dummy@@", "");
            tableNode.ImageIndex = 0;

            TreeNode viewNode = dbTn.Nodes.Add("Views");
            viewNode.Tag = new DBObject(NodeType.ViewHolder);
            viewNode.Nodes.Add("@@Dummy@@", "");
            viewNode.ImageIndex = 0;

            TreeNode spNode = dbTn.Nodes.Add("Stored Procedures");
            spNode.Tag = new DBObject(NodeType.SPHolder);
            spNode.Nodes.Add("@@Dummy@@", "");
            spNode.ImageIndex = 0;

            TreeNode functionNode = dbTn.Nodes.Add("Functions");
            functionNode.Tag = new DBObject(NodeType.FunctionHolder);
            functionNode.Nodes.Add("@@Dummy@@", "");
            functionNode.ImageIndex = 0;
        }

        #region protected override void OnBeforeExpand(TreeViewCancelEventArgs e)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnBeforeExpand(TreeViewCancelEventArgs e)
        {
            e.Node.Text += " (expanding...)";
        }
        #endregion

        #region protected override void OnAfterExpand(TreeViewEventArgs e)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnAfterExpand(TreeViewEventArgs e)
        {
            e.Node.Nodes.RemoveByKey("@@Dummy@@");
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
            WorkerArgs args = new WorkerArgs(e.Node, false);
            worker.RunWorkerAsync(args);
        }
        #endregion

        #region void worker_DoWork(object sender, DoWorkEventArgs e)
        /// <summary>
        /// This method is called when the worker's DoWork event has been fired.
        /// </summary>
        /// <param name="sender">The <see cref="object"/> that fired the event.</param>
        /// <param name="e">The <see cref="DoWorkEventArgs"/> of the event.</param>
        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            WorkerArgs args = (WorkerArgs)e.Argument;
            args.Children.AddRange(Refresh(args.Node, args.ForceRefresh));
            e.Result = args;
        }
        #endregion

        #region void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        /// <summary>
        /// This method is called when the worker's RunWorkerCompleted event has been fired.
        /// </summary>
        /// <param name="sender">The <see cref="object"/> that fired the event.</param>
        /// <param name="e">The <see cref="RunWorkerCompletedEventArgs"/> of the event.</param>
        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            WorkerArgs args = (WorkerArgs)e.Result;
            if (args.Node.Text.EndsWith(" (expanding...)"))
            {
                args.Node.Text = args.Node.Text.Substring(0, args.Node.Text.Length - 15);
            }
            args.Node.Nodes.AddRange(args.Children.ToArray());
        }
        #endregion

        #region private List<TreeNode> Refresh(TreeNode currentNode, bool forceRefresh)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="currentNode"></param>
        /// <param name="forceRefresh"></param>
        /// <returns></returns>
        private List<TreeNode> Refresh(TreeNode currentNode, bool forceRefresh)
        {
            List<TreeNode> nodeList = new List<TreeNode>();
            NodeType type = ((DBObject)currentNode.Tag).ObjectType;

            if (currentNode.Nodes.Count == 0 || forceRefresh)
            {
                TreeNode currentDB = (TreeNode)GetNodeByType(currentNode, NodeType.Database);
                TreeNode currentTable = (TreeNode)GetNodeByType(currentNode, NodeType.Table);
                TreeNode currentView = (TreeNode)GetNodeByType(currentNode, NodeType.View);
                TreeNode currentSP = (TreeNode)GetNodeByType(currentNode, NodeType.SP);
                TreeNode currentFunction = (TreeNode)GetNodeByType(currentNode, NodeType.Function);

                TreeNode tnColHolder;
                TreeNode tnKeyHolder;
                TreeNode tnConstraintHolder;
                TreeNode tnTriggerHolder;
                TreeNode tnIndexHolder;
                TreeNode tnSP;
                TreeNode tnParamHolder;
                TreeNode tnFunc;
                TreeNode tnFuncParamHolder;
                switch (type)
                {
                    case NodeType.TableHolder:
                        _server.Databases[currentDB.Text].PrefetchObjects(typeof(Table));
                        //_server.SetDefaultInitFields(typeof(Column), true);
                        foreach (Table tbl in _server.Databases[currentDB.Text].Tables)
                        {
                            TreeNode tnTbl = new TreeNode(tbl.Name, 3, 3);
                            tnTbl.Name = tbl.Name;
                            ITable table = new MSSqlTable(tbl);
                            //table.GetColumns();
                            tnTbl.Tag = new DBObject(NodeType.Table, table);
                            tnTbl.Nodes.Add("@@Dummy@@", "");

                            tnColHolder = tnTbl.Nodes.Add("Columns");
                            tnColHolder.Tag = new DBObject(NodeType.ColumnHolder);
                            tnColHolder.Nodes.Add("@@Dummy@@", "");

                            tnKeyHolder = tnTbl.Nodes.Add("Keys");
                            tnKeyHolder.Tag = new DBObject(NodeType.KeyHolder);
                            tnKeyHolder.Nodes.Add("@@Dummy@@", "");

                            tnConstraintHolder = tnTbl.Nodes.Add("Constraints");
                            tnConstraintHolder.Tag = new DBObject(NodeType.ConstraintHolder);
                            tnConstraintHolder.Nodes.Add("@@Dummy@@", "");

                            tnTriggerHolder = tnTbl.Nodes.Add("Triggers");
                            tnTriggerHolder.Tag = new DBObject(NodeType.TriggerHolder);
                            tnTriggerHolder.Nodes.Add("@@Dummy@@", "");

                            tnIndexHolder = tnTbl.Nodes.Add("Indexes");
                            tnIndexHolder.Tag = new DBObject(NodeType.IndexHolder);
                            tnIndexHolder.Nodes.Add("@@Dummy@@", "");

                            nodeList.Add(tnTbl);
                        }
                        break;
                    case NodeType.Table:
                        tnColHolder = new TreeNode("Columns");
                        tnColHolder.Tag = new DBObject(NodeType.ColumnHolder);
                        tnColHolder.Nodes.Add("@@Dummy@@", "");
                        nodeList.Add(tnColHolder);

                        tnKeyHolder = new TreeNode("Keys");
                        tnKeyHolder.Tag = new DBObject(NodeType.KeyHolder);
                        tnKeyHolder.Nodes.Add("@@Dummy@@", "");
                        nodeList.Add(tnKeyHolder);

                        tnConstraintHolder = new TreeNode("Constraints");
                        tnConstraintHolder.Tag = new DBObject(NodeType.ConstraintHolder);
                        tnConstraintHolder.Nodes.Add("@@Dummy@@", "");
                        nodeList.Add(tnConstraintHolder);

                        tnTriggerHolder = new TreeNode("Triggers");
                        tnTriggerHolder.Tag = new DBObject(NodeType.TriggerHolder);
                        tnTriggerHolder.Nodes.Add("@@Dummy@@", "");
                        nodeList.Add(tnTriggerHolder);

                        tnIndexHolder = new TreeNode("Indexes");
                        tnIndexHolder.Tag = new DBObject(NodeType.IndexHolder);
                        tnIndexHolder.Nodes.Add("@@Dummy@@", "");
                        nodeList.Add(tnIndexHolder);
                        break;
                    case NodeType.ConstraintHolder:
                    case NodeType.ColumnHolder:
                        List<string> constraints = new List<string>();
                        if (type == NodeType.ColumnHolder)
                        {
                            foreach (Column col in _server.Databases[currentDB.Text].Tables[currentTable.Text].Columns)
                            {
                                IColumn iCol = new MSSqlColumn(col.Parent, col);
                                TreeNode tnCol = new TreeNode(iCol.ToString());
                                tnCol.Tag = new DBObject(NodeType.Column);
                                tnCol.ImageIndex = col.InPrimaryKey ? 5 : col.IsForeignKey ? 6 : 4;
                                tnCol.SelectedImageIndex = tnCol.ImageIndex;

                                if (col.DefaultConstraint != null)
                                {
                                    constraints.Add(col.DefaultConstraint.Name);
                                }
                                nodeList.Add(tnCol);
                            }
                        }
                        if (type == NodeType.ConstraintHolder)
                        {
                            foreach (string constraint in constraints)
                            {
                                TreeNode tnConstraint = new TreeNode(constraint, 8, 8);
                                tnConstraint.Tag = new DBObject(NodeType.Constraint);
                                nodeList.Add(tnConstraint);
                            }
                        }
                        break;
                    case NodeType.KeyHolder:
                        foreach (Index index in _server.Databases[currentDB.Text].Tables[currentTable.Text].Indexes)
                        {
                            TreeNode tnKey = null;
                            switch (index.IndexKeyType)
                            {
                                case IndexKeyType.DriPrimaryKey:
                                    tnKey = new TreeNode(index.Name, 5, 5);
                                    tnKey.Tag = new DBObject(NodeType.Index);
                                    break;
                                case IndexKeyType.DriUniqueKey:
                                    tnKey = new TreeNode(index.Name, 7, 7);
                                    tnKey.Tag = new DBObject(NodeType.Index);
                                    break;
                            }
                            if (tnKey != null)
                            {
                                nodeList.Add(tnKey);
                            }

                        }
                        foreach (ForeignKey fk in _server.Databases[currentDB.Text].Tables[currentTable.Text].ForeignKeys)
                        {
                            TreeNode tnFK = new TreeNode(fk.Name, 6, 6);
                            tnFK.Tag = new DBObject(NodeType.Key);
                            nodeList.Add(tnFK);
                        }
                        break;
                    case NodeType.TriggerHolder:
                        foreach (Trigger trigger in _server.Databases[currentDB.Text].Tables[currentTable.Text].Triggers)
                        {
                            TreeNode tnTrigger = new TreeNode(trigger.Name, 9, 9);
                            tnTrigger.Tag = new DBObject(NodeType.Trigger);
                            nodeList.Add(tnTrigger);
                        }
                        break;
                    case NodeType.IndexHolder:
                        foreach (Index index in _server.Databases[currentDB.Text].Tables[currentTable.Text].Indexes)
                        {
                            TreeNode tnIdx = null;
                            switch (index.IndexKeyType)
                            {
                                case IndexKeyType.None:
                                    tnIdx = new TreeNode(index.Name, 10, 10);
                                    tnIdx.Tag = new DBObject(NodeType.Index);
                                    break;
                            }
                            if (tnIdx != null)
                            {
                                nodeList.Add(tnIdx);
                            }
                        }
                        break;
                    case NodeType.ViewHolder:
                        _server.Databases[currentDB.Text].PrefetchObjects(typeof(Microsoft.SqlServer.Management.Smo.View));
                        //_server.SetDefaultInitFields(typeof(Column), true);
                        foreach (Microsoft.SqlServer.Management.Smo.View view in _server.Databases[currentDB.Text].Views)
                        {
                            if (view.IsSystemObject)
                            {
                                continue;
                            }
                            IView vw = new MSSqlView(view);
                            TreeNode tnView = new TreeNode(view.Name, 12, 12);
                            tnView.Name = view.Name;
                            tnView.Tag = new DBObject(NodeType.View, vw);
                            tnView.Nodes.Add("@@Dummy@@", "");

                            tnColHolder = tnView.Nodes.Add("Columns");
                            tnColHolder.Tag = new DBObject(NodeType.ViewColumnHolder);
                            tnColHolder.Nodes.Add("@@Dummy@@", "");

                            tnTriggerHolder = tnView.Nodes.Add("Triggers");
                            tnTriggerHolder.Tag = new DBObject(NodeType.ViewTriggerHolder);
                            tnTriggerHolder.Nodes.Add("@@Dummy@@", "");

                            tnIndexHolder = tnView.Nodes.Add("Indexes");
                            tnIndexHolder.Tag = new DBObject(NodeType.ViewIndexHolder);
                            tnIndexHolder.Nodes.Add("@@Dummy@@", "");

                            nodeList.Add(tnView);
                        }
                        break;
                    case NodeType.View:
                        tnColHolder = new TreeNode("Columns");
                        tnColHolder.Tag = new DBObject(NodeType.ViewColumnHolder);
                        tnColHolder.Nodes.Add("@@Dummy@@", "");
                        nodeList.Add(tnColHolder);

                        tnTriggerHolder = new TreeNode("Triggers");
                        tnTriggerHolder.Tag = new DBObject(NodeType.ViewTriggerHolder);
                        tnTriggerHolder.Nodes.Add("@@Dummy@@", "");
                        nodeList.Add(tnTriggerHolder);

                        tnIndexHolder = new TreeNode("Indexes");
                        tnIndexHolder.Tag = new DBObject(NodeType.ViewIndexHolder);
                        tnIndexHolder.Nodes.Add("@@Dummy@@", "");
                        nodeList.Add(tnIndexHolder);
                        break;
                    case NodeType.ViewColumnHolder:
                        foreach (Column col in _server.Databases[currentDB.Text].Views[currentView.Text].Columns)
                        {
                            IColumn iCol = new MSSqlColumn(col.Parent, col);
                            TreeNode tnCol = new TreeNode(iCol.ToString());
                            tnCol.Tag = new DBObject(NodeType.Column);
                            tnCol.ImageIndex = col.InPrimaryKey ? 5 : 4;
                            tnCol.SelectedImageIndex = tnCol.ImageIndex;
                            nodeList.Add(tnCol);
                        }
                        break;
                    case NodeType.ViewTriggerHolder:
                        foreach (Trigger trigger in _server.Databases[currentDB.Text].Views[currentView.Text].Triggers)
                        {
                            TreeNode tnTrigger = new TreeNode(trigger.Name, 9, 9);
                            tnTrigger.Tag = new DBObject(NodeType.ViewTrigger);
                            nodeList.Add(tnTrigger);
                        }
                        break;
                    case NodeType.ViewIndexHolder:
                        foreach (Index index in _server.Databases[currentDB.Text].Views[currentView.Text].Indexes)
                        {
                            TreeNode tnIdx = new TreeNode(index.Name, 10, 10);
                            tnIdx.Tag = new DBObject(NodeType.ViewIndex);
                            nodeList.Add(tnIdx);
                        }
                        break;
                    case NodeType.SPHolder:
                        _server.Databases[currentDB.Text].PrefetchObjects(typeof(StoredProcedure));
                        //_server.SetDefaultInitFields(typeof(StoredProcedureParameter), true);
                        foreach (StoredProcedure sp in _server.Databases[currentDB.Text].StoredProcedures)
                        {
                            if (sp.IsSystemObject)
                            {
                                continue;
                            }
                            tnSP = new TreeNode(sp.Name, 13, 13);
                            tnSP.Name = sp.Name;
                            tnSP.Tag = new DBObject(NodeType.SP);

                            tnParamHolder = tnSP.Nodes.Add("Parameters");
                            tnParamHolder.Tag = new DBObject(NodeType.SPParamsHolder);
                            tnParamHolder.Nodes.Add("@@Dummy@@", "");

                            nodeList.Add(tnSP);
                        }
                        break;
                    case NodeType.SP:
                        tnParamHolder = new TreeNode("Parameters");
                        tnParamHolder.Tag = new DBObject(NodeType.SPParamsHolder);
                        tnParamHolder.Nodes.Add("@@Dummy@@", "");
                        nodeList.Add(tnParamHolder);
                        break;
                    case NodeType.SPParamsHolder:
                        foreach (StoredProcedureParameter spp in _server.Databases[currentDB.Text].StoredProcedures[currentSP.Text].Parameters)
                        {
                            TreeNode tnSPP = new TreeNode(spp.Name, 0, 0);
                            tnSPP.Tag = new DBObject(NodeType.SPParam);
                            nodeList.Add(tnSPP);
                        }
                        break;
                    case NodeType.FunctionHolder:
                        _server.Databases[currentDB.Text].PrefetchObjects(typeof(UserDefinedFunction));
                        //_server.SetDefaultInitFields(typeof(UserDefinedFunctionParameter), true);
                        foreach (UserDefinedFunction func in _server.Databases[currentDB.Text].UserDefinedFunctions)
                        {
                            if (func.IsSystemObject)
                            {
                                continue;
                            }
                            tnFunc = new TreeNode(func.Name, 14, 14);
                            tnFunc.Name = func.Name;
                            tnFunc.Tag = new DBObject(NodeType.Function);

                            tnFuncParamHolder = tnFunc.Nodes.Add("Parameters");
                            tnFuncParamHolder.Tag = new DBObject(NodeType.FunctionParamsHolder);
                            tnFuncParamHolder.Nodes.Add("@@Dummy@@", "");

                            nodeList.Add(tnFunc);
                        }
                        break;
                    case NodeType.Function:
                        tnFuncParamHolder = new TreeNode("Parameters");
                        tnFuncParamHolder.Tag = new DBObject(NodeType.FunctionParamsHolder);
                        tnFuncParamHolder.Nodes.Add("@@Dummy@@", "");
                        nodeList.Add(tnFuncParamHolder);
                        break;
                    case NodeType.FunctionParamsHolder:
                        foreach (UserDefinedFunctionParameter funcParam in _server.Databases[currentDB.Text].UserDefinedFunctions[currentFunction.Text].Parameters)
                        {
                            TreeNode tnFuncParam = new TreeNode(funcParam.Name, 0, 0);
                            tnFuncParam.Tag = new DBObject(NodeType.FunctionParam);
                            nodeList.Add(tnFuncParam);
                        }
                        break;

                }
            }
            return nodeList;
        }
        #endregion

        private void StoreDefaultInitFields(NodeType type)
        {
            //if (_server == null)
            //{
            //    return;
            //}
            //Type objectType = null;
            //switch (type)
            //{
            //    case NodeType.Server:                    
            //        objectType = typeof(DatabaseCollection);
            //        break;
            //    case NodeType.DatabaseHolder:
            //        objectType = typeof(Database);
            //        break;
            //    case NodeType.Database:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.TableHolder:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.Table:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.ColumnHolder:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.Column:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.KeyHolder:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.Key:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.ConstraintHolder:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.Constraint:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.TriggerHolder:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.Trigger:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.IndexHolder:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.Index:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.ViewHolder:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.View:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.SPHolder:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.SP:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.FunctionHolder:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.Function:
            //        objectType = typeof(Server);
            //        break;

            //    case NodeType.ViewColumnHolder:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.ViewColumn:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.ViewTriggerHolder:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.ViewTrigger:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.ViewIndexHolder:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.ViewIndex:
            //        objectType = typeof(Server);
            //        break;

            //    case NodeType.SPParamsHolder:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.SPParam:
            //        objectType = typeof(Server);
            //        break;

            //    case NodeType.FunctionParamsHolder:
            //        objectType = typeof(Server);
            //        break;
            //    case NodeType.FunctionParam:
            //        objectType = typeof(Server);
            //        break;
            //}
            //if (_defaultInitFields[objectType] == null)
            //{
            //    _defaultInitFields.Add(objectType, _server.GetDefaultInitFields(objectType));
            //}
            //else
            //{
            //    _defaultInitFields[objectType] = _server.GetDefaultInitFields(objectType);
            //}
        }

        private void RestoreDefaultInitFields(Type objectType)
        {
            if (_server == null || _defaultInitFields[objectType] == null)
            {
                return;
            }
            _server.SetDefaultInitFields(objectType, _defaultInitFields[objectType]);
        }

        #region private TreeNode GetNodeByType(TreeNode currentNode, NodeType nodeType)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="currentNode"></param>
        /// <param name="nodeType"></param>
        /// <returns></returns>
        private TreeNode GetNodeByType(TreeNode currentNode, NodeType nodeType)
        {
            TreeNode tn = currentNode;
            while (tn.Parent != null)
            {
                if (tn.Parent.Tag != null)
                {
                    NodeType tp = ((DBObject)tn.Parent.Tag).ObjectType;
                    if (tp == nodeType)
                    {
                        return tn.Parent;
                    }
                }
                tn = tn.Parent;
            }
            return null;
        }
        #endregion

        public TreeNode GetNodeByName(string name, NodeType nodeType)
        {
            foreach (TreeNode tn in this.Nodes)
            {
                NodeType tp = ((DBObject)tn.Tag).ObjectType;
                if (tn.Text == name && tp == nodeType)
                {
                    return tn;
                }
                else
                {
                    foreach (TreeNode child in tn.Nodes)
                    {
                        TreeNode ret = GetChildNodeByName(child, name, nodeType);
                        if (ret != null)
                        {
                            return ret;
                        }
                    }
                }
            }
            return null;
        }

        private TreeNode GetChildNodeByName(TreeNode root, string name, NodeType nodeType)
        {
            foreach (TreeNode tn in root.Nodes)
            {
                if (tn.Tag == null)
                {
                    return null;
                }
                NodeType tp = ((DBObject)tn.Tag).ObjectType;
                if (tn.Text == name && tp == nodeType)
                {
                    return tn;
                }
                else
                {
                    foreach (TreeNode child in tn.Nodes)
                    {
                        TreeNode ret = GetChildNodeByName(child, name, nodeType);
                        if (ret != null)
                        {
                            return ret;
                        }
                    }
                }
            }
            return null;
        }

        #region private void InitializeComponent()
        /// <summary>
        /// 
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DBTreeView));
            this.nodeImageList = new System.Windows.Forms.ImageList(this.components);
            this.contextMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
            this.toolStripRefresh = new System.Windows.Forms.ToolStripMenuItem();
            this.contextMenu.SuspendLayout();
            this.SuspendLayout();
            // 
            // nodeImageList
            // 
            this.nodeImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("nodeImageList.ImageStream")));
            this.nodeImageList.TransparentColor = System.Drawing.Color.Transparent;
            this.nodeImageList.Images.SetKeyName(0, "folder.ico");
            this.nodeImageList.Images.SetKeyName(1, "server.ico");
            this.nodeImageList.Images.SetKeyName(2, "database.ico");
            this.nodeImageList.Images.SetKeyName(3, "table.ico");
            this.nodeImageList.Images.SetKeyName(4, "column.ico");
            this.nodeImageList.Images.SetKeyName(5, "pk.ico");
            this.nodeImageList.Images.SetKeyName(6, "fk.ico");
            this.nodeImageList.Images.SetKeyName(7, "lk.ico");
            this.nodeImageList.Images.SetKeyName(8, "constraint.ico");
            this.nodeImageList.Images.SetKeyName(9, "trigger.ico");
            this.nodeImageList.Images.SetKeyName(10, "index.ico");
            this.nodeImageList.Images.SetKeyName(11, "statistics.ico");
            this.nodeImageList.Images.SetKeyName(12, "view.ico");
            this.nodeImageList.Images.SetKeyName(13, "sp.ico");
            this.nodeImageList.Images.SetKeyName(14, "function.ico");
            // 
            // contextMenu
            // 
            this.contextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.toolStripRefresh});
            this.contextMenu.Name = "contextMenu";
            this.contextMenu.Size = new System.Drawing.Size(124, 26);
            this.contextMenu.ItemClicked += new System.Windows.Forms.ToolStripItemClickedEventHandler(this.contextMenu_ItemClicked);
            // 
            // toolStripRefresh
            // 
            this.toolStripRefresh.Name = "toolStripRefresh";
            this.toolStripRefresh.Size = new System.Drawing.Size(123, 22);
            this.toolStripRefresh.Text = "Refresh";
            // 
            // DBTreeView
            // 
            this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.ContextMenuStrip = this.contextMenu;
            this.ImageIndex = 0;
            this.ImageList = this.nodeImageList;
            this.ItemHeight = 18;
            this.LineColor = System.Drawing.Color.Black;
            this.SelectedImageIndex = 0;
            this.contextMenu.ResumeLayout(false);
            this.ResumeLayout(false);

        }
        #endregion

        #region private void contextMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        /// <summary>
        /// This method is called when the contextMenu's ItemClicked event has been fired.
        /// </summary>
        /// <param name="sender">The <see cref="object"/> that fired the event.</param>
        /// <param name="e">The <see cref="ToolStripItemClickedEventArgs"/> of the event.</param>
        private void contextMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            if (e.ClickedItem.Name == "toolStripRefresh" && this.SelectedNode != null)
            {
                BackgroundWorker worker = new BackgroundWorker();
                worker.DoWork += new DoWorkEventHandler(worker_DoWork);
                WorkerArgs args = new WorkerArgs(this.SelectedNode, true);
                worker.RunWorkerAsync(args);
            }
        }
        #endregion
    }

    internal class WorkerArgs
    {
        private TreeNode _node;
        #region public TreeNode Node
        /// <summary>
        /// Gets the Node of the WorkerArgs
        /// </summary>
        /// <value></value>
        public TreeNode Node
        {
            get { return _node; }
        }
        #endregion

        private bool _forceRefresh;
        #region public bool ForceRefresh
        /// <summary>
        /// Gets the ForceRefresh of the WorkerArgs
        /// </summary>
        /// <value></value>
        public bool ForceRefresh
        {
            get { return _forceRefresh; }
        }
        #endregion

        List<TreeNode> _children = new List<TreeNode>();
        public List<TreeNode> Children
        {
            get { return _children; }
        }

        #region public WorkerArgs(TreeNode node, bool forceRefresh)
        /// <summary>
        /// Initializes a new instance of the <b>WorkerArgs</b> class.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="forceRefresh"></param>
        public WorkerArgs(TreeNode node, bool forceRefresh)
        {
            _node = node;
            _forceRefresh = forceRefresh;
        }
        #endregion
    }

    public class DBObject
    {
        private NodeType _objectType;
        public NodeType ObjectType
        {
            get { return _objectType; }
        }

        private object _underlayingObject;
        public object UnderlayingObject
        {
            get { return _underlayingObject; }
            set { _underlayingObject = value; }
        }

        public DBObject(NodeType objectType)
            : this(objectType, null)
        {
        }

        public DBObject(NodeType objectType, object underlayingObject)
        {
            _objectType = objectType;
            _underlayingObject = underlayingObject;
        }
    }
}
